using System;
using System.Collections.Generic;
using Heaven.Mathematics;
using Heaven.Graphics;
using Heaven.Geometry;
using Heaven.Engine.Animation;
using Heaven.Engine.Transformations;

namespace Heaven.Engine
{
    /// <summary>
    /// Represents element of render graph
    /// </summary>
    public abstract class Node
    {
        #region Events

        // Weak events
        WeakMulticastDelegate invalidated = new WeakMulticastDelegate();

        /// <summary>
        /// Occurs when the node or one of its parts have been changed
        /// </summary>
        public event EventHandler Invalidated
        {
            add { invalidated.Add(value); }
            remove { invalidated.Remove(value); }
        }
           
                
        #endregion

        #region Fields

        /// <summary>
        /// Additional data
        /// </summary>
        object tag;

        /// <summary>
        /// Parents with the node
        /// </summary>
        protected List<Node> parents = new List<Node>(1);

        #endregion

        #region Properties


        /*/// <summary>
        /// Is the node attached to a render graph?
        /// </summary>
        internal abstract bool IsAttached
        {
            get;
        }*/

        /// <summary>
        /// Additional data
        /// </summary>
        public object Tag
        {
            get { return tag; }
            set { tag = value; }
        }              
               

        #endregion

        #region Methods

        /// <summary>
        /// Attachs node (non-user method, it is for engine purpose only)
        /// </summary>
        /// <param name="node">Node</param>
        internal virtual void Attach(Node node)
        {
            if(!parents.Contains(node)) parents.Add(node);
        }

        /// <summary>
        /// Attachs node (non-user method, it is for engine purpose only)
        /// </summary>
        /// <param name="renderer">Renderer</param>
        internal virtual void Dettach(Node node)
        {
            parents.Remove(node);
        }

        /// <summary>
        /// Invalidates the content of the node
        /// </summary>
        public void Invalidate()
        {
            invalidated.Invoke(this, EventArgs.Empty);
        }

        /// <summary>
        /// Enumerates nodes
        /// </summary>
        /// <returns>A System.Collections.Generic.IEnumerable<Visual> that 
        /// can be used to iterate through the collection</returns>
        internal abstract IEnumerable<Visual> Enumerate();
                
        /// <summary>
        /// Adds the visual to render queue
        /// </summary>
        /// <param name="visual">Visual</param>
        /// <param name="technique">Visual's current technique (in the moment of request)</param>
        internal virtual void RegisterToRenderQueue(Visual visual, Technique technique)
        {
            foreach (Node node in parents)
            {
                node.RegisterToRenderQueue(visual, technique);
            }
        }

        /// <summary>
        /// Removes the visual from render queue
        /// </summary>
        /// <param name="visual">Visual's current technique (in the moment of request)</param>
        internal virtual void RemoveFromRenderQueue(Visual visual, Technique technique)
        {
            foreach (Node node in parents)
            {
                node.RemoveFromRenderQueue(visual, technique);
            }
        }

        #endregion
    }

    /// <summary>
    /// This is delegate for render queue request
    /// </summary>
    /// <param name="visual">Visual</param>
    /// <param name="technique">Visual's current technique (in the moment of request)</param>
    public delegate void RenderQueueRequestHandler(Visual visual, Technique technique);

    /// <summary>
    /// This is delegate for event in which a value changed
    /// </summary>
    /// <param name="sender">A sender</param>
    /// <param name="args">An argument of event</param>
    public delegate void ValueChangedEventHandler<T>(object sender, ValueChangedEventAgs<T> args);

    /// <summary>
    /// This class contains event data 
    /// relative to changing a property
    /// </summary>
    public class ValueChangedEventAgs<T> : EventArgs
    {
        /// <summary>
        /// The previous value
        /// </summary>
        public readonly T Previous;

        /// <summary>
        /// The new value
        /// </summary>
        public readonly T Current;

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="oldValue">The previous value</param>
        /// <param name="newValue">The new value</param>
        public ValueChangedEventAgs(T oldValue, T newValue)
        {
            Previous = oldValue;
            Current = newValue;
        }
    }

    /*/// <summary>
    /// This class contains event data 
    /// relative to changing a node
    /// </summary>
    public class VisualEventAgs : EventArgs
    {
        /// <summary>
        /// The previous value
        /// </summary>
        public readonly Visual Visual;
               
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="visual">Visual</param>
        public VisualEventAgs(Visual visual)
        {
            Visual = visual;
        }
    }*/
}
